#include "DInput.h"
#include "d3dUtil.h"
#include "d3dApp.h"
#include <commctrl.h>
#include <basetsd.h>

// Changes made by zach 01/28/08
BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext);
BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext );

IDirectInputDevice8		*mJoystick[MAXPLAYERS];


DIJOYSTATE2				js[MAXPLAYERS];


DIDEVCAPS				dcJoystick[MAXPLAYERS];

IDirectInput8			*mDInput;

int Count = 0;

DInput* gDInput = 0;

DInput::DInput(DWORD keyboardCoopFlags, DWORD mouseCoopFlags, DWORD joystickCoopFlags)
{
	//clear the memory
	for(int i = 0; i < MAXPLAYERS; i++)
	{
		ZeroMemory(&js[i], sizeof(js[i]));
	}

//	ZeroMemory(&js2, sizeof(js2));

	//create Direct Input Object
	HR(DirectInput8Create(gd3dApp->getAppInstance(), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&mDInput, 0));

	HR(mDInput->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, NULL, DIEDFL_ATTACHEDONLY));
	Count = 0;

	if(mJoystick[0] == NULL)
	{
		MessageBox(gd3dApp->getMainWindowHandle(), "No Joystick 1 Found", "Error", 0);
		PostQuitMessage(0);
	}
	else
	{
		HR(mJoystick[0]->SetDataFormat(&c_dfDIJoystick2));
		HR(mJoystick[0]->SetCooperativeLevel(gd3dApp->getMainWindowHandle(), joystickCoopFlags));
		dcJoystick[0].dwSize = sizeof(DIDEVCAPS);
		HR(mJoystick[0]->GetCapabilities(&dcJoystick[0]));
		HR(mJoystick[0]->EnumObjects(EnumObjectsCallback, NULL, DIDFT_ALL));

		HR(mJoystick[0]->Acquire());
	}

	
	Count++;

	if(mJoystick[1] == NULL)
	{
		MessageBox(gd3dApp->getMainWindowHandle(), "No Joystick 2 Found", "Error", 0);
		//PostQuitMessage(0);
	}
	else
	{
		HR(mJoystick[1]->SetDataFormat(&c_dfDIJoystick2));
		HR(mJoystick[1]->SetCooperativeLevel(gd3dApp->getMainWindowHandle(), joystickCoopFlags));
		dcJoystick[1].dwSize = sizeof(DIDEVCAPS);
		HR(mJoystick[1]->GetCapabilities(&dcJoystick[1]));
		HR(mJoystick[1]->EnumObjects(EnumObjectsCallback, NULL, DIDFT_ALL));
		HR(mJoystick[1]->Acquire());
	}
}

BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE *pdidInstance, VOID* pContext)
{


	HRESULT hr;

    // Obtain an interface to the enumerated joystick.
	hr = mDInput->CreateDevice(pdidInstance->guidInstance, &mJoystick[Count], NULL);
	if(FAILED(hr)) 
		return DIENUM_CONTINUE;

	else
	{
		Count++;
		if (Count >= 2)
		{
			return DIENUM_STOP;
		}
	}

    return DIENUM_CONTINUE;
}

void DInput::poll()
{
	//poll the keyboard, find out what state keys are in
//	HRESULT hr = mKeyboard->GetDeviceState(sizeof(mKeyboardState), (void**)&mKeyboardState);

//	if(FAILED(hr))
//	{
		//keyboard lost, zero out keyboard data structure
//		ZeroMemory(mKeyboardState, sizeof(mKeyboardState));

		//try to acquire for next time we poll
//		hr = mKeyboard->Acquire();
///	}

	//poll mouse
//	hr = mMouse->GetDeviceState(sizeof(DIMOUSESTATE2), (void**)&mMouseState);

//	if(FAILED(hr))
//	{
//		//mouse lost, zero out data structure
//		ZeroMemory(&mMouseState, sizeof(mMouseState));

		//try and acquire for next poll
//		mMouse->Acquire();
//	}
}

void DInput::pollJoystick()
{
	HRESULT hr;
//	HRESULT hr2;
	hr = mJoystick[0]->Poll();
//	hr2 = mJoystick[1]->Poll();


	if(FAILED(hr))
	{
		for(int i = 0; i < MAXPLAYERS; i++)
		{
		//not sure if this is needed
		//joystick lost, zero our data structure
		ZeroMemory(&js[i], sizeof(js[i]));
		//ZeroMemory(&js2, sizeof(js2));
		//try and acquire for next poll
		mJoystick[0]->Poll();
		}
		//try and acquire for next poll
		//mJoystick[1]->Poll();

	}
	//if(FAILED(hr2))
	//{
	//	//not sure if this is needed
	//	//joystick lost, zero our data structure
	//	//ZeroMemory(&js, sizeof(js));
	//	ZeroMemory(&js2, sizeof(js2));
	//	//try and acquire for next poll
	//	//mJoystick[0]->Poll();

	//	//try and acquire for next poll
	//	mJoystick[1]->Poll();

	//}
}

void DInput::onLostDevice()
{
	HRESULT hr;
	for(int i = 0; i < MAXPLAYERS; i++)
	{
		ZeroMemory(&js[i], sizeof(js[i]));
	}

	if(mJoystick[0] != NULL)
		hr = mJoystick[0]->Acquire();

	if(mJoystick[1] != NULL)
		hr = mJoystick[1]->Acquire();
}

bool DInput::keyDown(unsigned char key)
{
	//performing a bitwise operation to see if key is down, if the bits 0x80 are set, the key is 
	//considered to be pressed
	return false;// ((mKeyboardState[key] & 0x80) != 0);
	
}

bool DInput::mouseButtonDown(int button)
{
	return (mMouseState.rgbButtons[button] & 0x80) != 0;
}

float DInput::mouseDX()
{
	return (float)mMouseState.lX;
}

float DInput::mouseDY()
{
	return (float)mMouseState.lY;
}

float DInput::mouseDZ()
{
	return (float)mMouseState.lZ;
}
DInput::~DInput()
{
	//release Direct Input Object
	ReleaseCOM(mDInput);
	
	//unacquire devices, give them back to the system!!!
//	mKeyboard->Unacquire();
//	mMouse->Unacquire();
	if(mJoystick[0] != NULL)
	{
		mJoystick[0]->Unacquire();
		ReleaseCOM(mJoystick[0]);
	}

	if(mJoystick[1] != NULL)
	{
		mJoystick[1]->Unacquire();
		ReleaseCOM(mJoystick[1]);
	}

	//release the devices
//	ReleaseCOM(mKeyboard);
//	ReleaseCOM(mMouse);
	
//	ReleaseCOM(mJoystick[1]);
}

BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi,
                                   VOID* pContext )
{
    // For axes that are returned, set the DIPROP_RANGE property for the
    // enumerated axis in order to scale min/max values.
    if( pdidoi->dwType & DIDFT_AXIS )
    {
        DIPROPRANGE diprg; 
        diprg.diph.dwSize       = sizeof(DIPROPRANGE); 
        diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
        diprg.diph.dwHow        = DIPH_BYID; 
        diprg.diph.dwObj        = pdidoi->dwType; // Specify the enumerated axis
        diprg.lMin              = -100; 
        diprg.lMax              = +100; 
    
        // Set the range for the axis
        if( FAILED( mJoystick[Count]->SetProperty( DIPROP_RANGE, &diprg.diph ) ) ) 
            return DIENUM_STOP;
	}
	return DIENUM_CONTINUE;
}